package com.hontech.desktoppastacooker.utils

import android.os.Handler
import android.os.HandlerThread
import android.os.Looper
import android.view.View
import android.widget.EditText
import com.hontech.desktoppastacooker.conn.SerialPortMod
import com.hontech.desktoppastacooker.conn.serial.SerialType
import com.hontech.desktoppastacooker.ui.window.Dialog
import com.hontech.desktoppastacooker.ui.window.showErr
import com.hontech.desktoppastacooker.ui.window.showProg
import kotlinx.coroutines.*
import kotlinx.serialization.json.Json
import org.greenrobot.eventbus.EventBus
import org.greenrobot.eventbus.EventBusBuilder
import java.lang.Runnable


private class HandlerTask(name: String) : HandlerThread(name) {

    init {
        start()
    }
}

object AppTask : Handler(Looper.getMainLooper())

object ConnTask : Handler(HandlerTask("conn").looper)

object NetTask : Handler(HandlerTask("net").looper)

class PromiseTask<T> (val task: ()-> T) : Runnable {

    private val promise = CompletableDeferred<T>()

    suspend fun await(executor: Handler): T {
        executor.post(this)
        return promise.await()
    }

    override fun run() {

        try {
            val ret = task()
            promise.complete(ret)
        } catch (e: Exception) {
            promise.completeExceptionally(e)
        }
    }
}

val appCoroutine = CoroutineScope(Job() + Dispatchers.Main)

val eventBus = EventBus.builder().logNoSubscriberMessages(false).build()

suspend fun <T> CompletableDeferred<T>.await(timeout: Long): T {
    return withTimeout(timeout) { await() }
}

private var globalClickTick = System.currentTimeMillis()

val defJson = Json {
    encodeDefaults = true
    ignoreUnknownKeys = true
}

fun View.onClick(cb: suspend ()-> Unit) {
    this.setOnClickListener {
        val cur = System.currentTimeMillis()
        val flag = (cur - globalClickTick) > 500
        globalClickTick = cur
        if (!flag) {
            return@setOnClickListener
        }
        appCoroutine.launch { cb() }
    }
}

fun EditText.toInt() = this.text.toString().toInt()

suspend fun ctrl(title: String, msg: String, timeout: Long, cmd: Int, args: Array<SerialType>) {

    try {
        val ret = SerialPortMod.request(timeout, cmd, args)
        ret.assertErr()
    } catch (e: Exception) {
        e.printStackTrace()
        showErr(title, "$msg ${e.message}")
    }
}

suspend fun wrapDialog(title: String, msg: String, cb: suspend ()-> Unit) {

    val dialog = showProg(title, msg)
    try {
        cb()
        dialog.success("$msg 成功")
    } catch (e: Exception) {
        e.printStackTrace()
        dialog.error(e)
    }
}

suspend fun wrapReq(
    title: String,
    msg: String,
    timeout: Long,
    cmd: Int,
    args: Array<SerialType>) {

    wrapDialog(title, msg) {
        val ret = SerialPortMod.request(timeout, cmd, args)
        ret.assertErr()
    }
}

